package ca.usherbrooke.mainApp.view.newSimulation;

import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import ca.usherbrooke.utils.FormUtility;

public class NewSimulationPanel extends JPanel {

	private static final long serialVersionUID = 1L;

	// main frame
	private final JTextField nameTextField;
	private final JTextField mapTextField;
	private final JTextField entityImageTextField;
	private final JTextField equipmentIamgeTextField;
	private final JTextField entityTextField;
	private final JTextField equipmentTextField;

	private final JButton selectMapButton;
	private final JButton selectEntityImagesButton;
	private final JButton selectEquipmentImageButton;
	private final JButton addEntityButton;
	private final JButton addEquipmentButton;
	private final JButton createSimulationButton;

	private final JButton removeEntityButton;
	private final JButton removeEquipmentButton;
	private final JButton createEntityProperty;
	private final JButton createEquipmentProperty;

	private final JFileChooser fileChooser;
	private final JList entityList;
	private final DefaultListModel entityListModel;
	private final JList equipmentList;
	private final DefaultListModel equipmentListModel;

	private final FormUtility form;
	private final JPanel forumPanel;
	private final JPanel listPanel;
	private final JPanel createPropsPanel;

	private final EquipmentPropertyPanel equipmentPropertyPanel;
	private final EntityPropertyPanel entityPropertyPanel;
	private final String fileSeparator;

	public NewSimulationPanel() {
		super();

		fileSeparator = Character.toString(File.separatorChar);
		// set utility
		form = new FormUtility();

		// text field
		nameTextField = new JTextField(20);
		mapTextField = new JTextField(20);
		entityImageTextField = new JTextField(20);
		equipmentIamgeTextField = new JTextField(20);
		entityTextField = new JTextField(20);
		equipmentTextField = new JTextField(20);

		// button
		selectMapButton = new JButton("Select map");
		selectEntityImagesButton = new JButton("Select image");
		selectEquipmentImageButton = new JButton("Select image");
		addEntityButton = new JButton("Add Entity");
		addEquipmentButton = new JButton("Add Equipment");
		createSimulationButton = new JButton("Create Simulation");
		removeEntityButton = new JButton("Remove Entity");
		removeEntityButton.setEnabled(false);
		removeEquipmentButton = new JButton("Remove Equipment");
		removeEquipmentButton.setEnabled(false);

		createEntityProperty = new JButton("Create Entity props");
		createEquipmentProperty = new JButton("Create equipment props");

		// list
		entityList = new JList();
		entityListModel = new DefaultListModel();
		entityList.setModel(entityListModel);

		equipmentList = new JList();
		equipmentListModel = new DefaultListModel();
		equipmentList.setModel(equipmentListModel);

		// panel
		forumPanel = new JPanel(new GridBagLayout());
		forumPanel.setBorder(BorderFactory.createTitledBorder("Forum"));
		listPanel = new JPanel(new GridBagLayout());
		listPanel.setBorder(BorderFactory
				.createTitledBorder("Entity List / Equipment List"));
		createPropsPanel = new JPanel(new FlowLayout());

		// name
		form.addLabel("Name: ", forumPanel);
		form.addMiddleField(nameTextField, forumPanel);
		form.addLastField(new JLabel(""), forumPanel);

		// map
		form.addLabel("Map: ", forumPanel);
		form.addMiddleField(mapTextField, forumPanel);
		form.addLastField(selectMapButton, forumPanel);

		// entity image
		form.addLabel("Entity Image: ", forumPanel);
		form.addMiddleField(entityImageTextField, forumPanel);
		form.addLastField(selectEntityImagesButton, forumPanel);

		// equipment image
		form.addLabel("Equipment Image: ", forumPanel);
		form.addMiddleField(equipmentIamgeTextField, forumPanel);
		form.addLastField(selectEquipmentImageButton, forumPanel);

		// entity Object
		form.addLabel("Entity Object: ", forumPanel);
		form.addMiddleField(entityTextField, forumPanel);
		form.addLastField(addEntityButton, forumPanel);

		// equipment Object
		form.addLabel("Equipment Object: ", forumPanel);
		form.addMiddleField(equipmentTextField, forumPanel);
		form.addLastField(addEquipmentButton, forumPanel);

		// add button props
		createPropsPanel.add(createEntityProperty);
		createPropsPanel.add(createEquipmentProperty);

		form.addLabel(new JLabel(""), forumPanel);
		form.addMiddleField(createPropsPanel, forumPanel);
		form.addLastField(new JLabel(""), forumPanel);

		// create simulation button
		form.addLabel(new JLabel(""), forumPanel);
		form.addMiddleField(createSimulationButton, forumPanel);

		// list panel
		form.addLabel(new JLabel(""), listPanel);
		form.addMiddleField(entityList, listPanel);
		form.addLastField(equipmentList, listPanel);

		form.addLabel(new JLabel(""), listPanel);
		form.addMiddleField(removeEntityButton, listPanel);
		form.addLastField(removeEquipmentButton, listPanel);

		// entity property and equipment property panel
		entityPropertyPanel = new EntityPropertyPanel(this);
		equipmentPropertyPanel = new EquipmentPropertyPanel(this);

		// add panel to main panel
		this.setLayout(new FlowLayout());
		this.add(forumPanel, JPanel.TOP_ALIGNMENT);
		this.add(listPanel, JPanel.TOP_ALIGNMENT);

		// file chooser
		fileChooser = new JFileChooser();

		// disable simulation creation
		createSimulationButton.setEnabled(false);

		initListener();
	}

	private void initListener() {
		createSimulationButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createSimulation();

			}
		});

		selectMapButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				selectMap();
				validate();
			}
		});

		selectEntityImagesButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				selectEntityImage();
				validate();
			}
		});

		selectEquipmentImageButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				selectequipmentImage();
				validate();
			}
		});

		addEntityButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				addEntities();
				validate();
			}
		});

		addEquipmentButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				addEquipments();
				validate();
			}

		});

		removeEntityButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				removeEntityFromList();
				validate();
			}
		});

		removeEquipmentButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				removeEquipmentFromList();
				validate();
			}
		});

		createEntityProperty.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				loadEntityPropertyPanel();
			}
		});

		createEquipmentProperty.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				loadEquipmentPropertyPanel();
			}
		});

	}

	protected void loadEquipmentPropertyPanel() {
		this.remove(entityPropertyPanel);
		this.add(equipmentPropertyPanel);
		revalidate();

	}

	protected void loadEntityPropertyPanel() {
		this.remove(equipmentPropertyPanel);
		this.add(entityPropertyPanel);
		revalidate();
	}

	protected void createSimulation() {

		// String fileSeparator = Character.toString(File.separatorChar);
		Boolean simulationNameIsSet = false;
		Boolean mapNameIsSet = false;
		Boolean entityImageNameIsSet = false;
		Boolean equipmentImageNameIsSet = false;
		Boolean entityIsAdded = false;
		Boolean equipmentIsAdded = false;

		Boolean succes;
		String root;
		String folder;
		String targetFolder;
		int index = -1;
		int size = 0;

		// validate simulation name
		String str = nameTextField.getText();
		if (!str.trim().equalsIgnoreCase(" ")) {
			simulationNameIsSet = true;
		}

		// validate map name
		str = mapTextField.getText();
		if (!str.trim().equalsIgnoreCase(" ")) {
			index = str.indexOf(".tmx");
			if (index != -1) {
				mapNameIsSet = true;
			}
		}

		// validate entity image name
		str = entityImageTextField.getText();
		if (!str.trim().equalsIgnoreCase(" ")) {
			index = str.lastIndexOf(".");
			if (index != -1) {
				entityImageNameIsSet = true;
			}
		}

		// validate equipment image name
		str = equipmentIamgeTextField.getText();
		if (!str.trim().equalsIgnoreCase(" ")) {
			index = str.lastIndexOf(".");
			if (index != -1) {
				equipmentImageNameIsSet = true;
			}
		}

		// validate entity object
		index = 0;
		index = entityListModel.getSize();
		if (index != 0) {
			entityIsAdded = true;
		}

		// validate equipment object
		index = 0;
		index = equipmentListModel.getSize();
		if (index != 0) {
			equipmentIsAdded = true;
		}

		// validate simulation
		File file = null;
		if (simulationNameIsSet && mapNameIsSet && entityImageNameIsSet
				&& equipmentImageNameIsSet && entityIsAdded && equipmentIsAdded) {

			// simulation folder
			succes = false;
			root = "user_simulation" + fileSeparator
					+ nameTextField.getText().trim();
			file = new File(root);

			succes = file.mkdirs();
			if (!succes) {
				alertMessage("simulation folder exit");
			}

			// entity folder
			succes = false;
			str = root + fileSeparator + "entity";
			succes = new File(str).mkdirs();

			if (!succes) {
				alertMessage("entity folder exist");
			}

			// equipment folder
			succes = false;
			str = root + fileSeparator + "equipment";
			succes = new File(str).mkdirs();

			if (!succes) {
				alertMessage("equipment folder exist");
			}

			// img folder
			succes = false;
			str = root + fileSeparator + "imgs";
			succes = new File(str).mkdirs();

			if (!succes) {
				alertMessage("images folder exist");
			}

			// props folder
			succes = false;
			str = root + fileSeparator + "props";
			succes = new File(str).mkdirs();

			if (!succes) {
				alertMessage("props folder exist");
			}

			// copy file from
			// select map
			str = mapTextField.getText();
			addFiles(str, root);

			// select entity image
			str = entityImageTextField.getText();
			folder = root + fileSeparator + "imgs";
			addFiles(str, folder);

			// select equipment image
			str = equipmentIamgeTextField.getText();
			folder = root + fileSeparator + "imgs";
			addFiles(str, folder);

			// add entity object (we have to take entity object from the same
			// directory)

			size = entityListModel.getSize();
			str = entityTextField.getText();
			folder = str.substring(0, str.lastIndexOf(fileSeparator));
			targetFolder = root + fileSeparator + "entity";

			for (int i = 0; i < size; i++) {
				str = folder + fileSeparator + (String) entityListModel.get(i);
				addFiles(str, targetFolder);
			}

			// add equipment object
			size = equipmentListModel.getSize();
			str = equipmentTextField.getText();
			folder = str.substring(0, str.lastIndexOf(fileSeparator));
			targetFolder = root + fileSeparator + "equipment";

			for (int i = 0; i < size; i++) {
				str = folder + fileSeparator
						+ (String) equipmentListModel.get(i);
				addFiles(str, targetFolder);
			}

			// create "properties.txt" file
			createFile("properties.txt", root);
			// alert message
			JOptionPane.showMessageDialog(null, "simulation folder is created",
					"Alert", JOptionPane.INFORMATION_MESSAGE);

		} else {

			// delete the directory
			deleteDir(file);
			alertMessage("simulation is not valide...Revalidate the entries");
		}// end else
	}

	private void createFile(String str, String root) {
		String content = null;
		FileOutputStream to = null;
		String mapName = mapTextField.getText();
		mapName = mapName.substring(mapName.lastIndexOf(fileSeparator) + 1);
		File file = new File(root + fileSeparator + str);
		content = "windows_name_key=Virtual World for Intelligent Agent"
				+ "\r\n" + "tiled_map_path_key=." + fileSeparator + mapName
				+ "\r\n" + "frame_rate_key=50" + "\r\n" + "factor_zoom_key=1.0"
				+ "\r\n" + "force_exit_key=false" + "\r\n"
				+ "speed_factor_key=1.0";
		try {
			to = new FileOutputStream(file);
			to.write(content.getBytes());

		} catch (FileNotFoundException e) {
			alertMessage(e.getMessage());
		} catch (IOException e) {
			alertMessage(e.getMessage());
		} finally {
			try {
				to.close();
			} catch (IOException e) {
				alertMessage(e.getMessage());
			}
		}
	}

	private void addFiles(String source, String targetFolder) {
		String str = source.substring(source.lastIndexOf(fileSeparator) + 1);
		String targetfile = targetFolder + fileSeparator + str;
		try {
			copy(source, targetfile);
		} catch (IOException e) {
			alertMessage(e.getMessage());
		}
	}

	private void removeEquipmentFromList() {

		int indexToRemove = -1;
		indexToRemove = equipmentList.getSelectedIndex();
		if (indexToRemove != -1) {
			equipmentListModel.removeElementAt(indexToRemove);
			if (equipmentListModel.getSize() == 0) {
				removeEquipmentButton.setEnabled(false);
			}
		}
		validate();
	}

	private void removeEntityFromList() {

		int indexToRemove = -1;
		indexToRemove = entityList.getSelectedIndex();
		if (indexToRemove != -1) {
			entityListModel.removeElementAt(indexToRemove);
			if (entityListModel.getSize() == 0) {
				removeEntityButton.setEnabled(false);
			}
		}

	}

	private void addEquipments() {
		selectFile(equipmentTextField);
		String str = equipmentTextField.getText();
		str = validateFileName(str);
		if (str != null) {
			equipmentListModel.addElement(str);
			if (equipmentListModel.getSize() == 1) {
				removeEquipmentButton.setEnabled(true);
			}
		}
	}

	private void addEntities() {
		selectFile(entityTextField);
		String str = entityTextField.getText();
		str = validateFileName(str);
		if (str != null) {
			entityListModel.addElement(str);
			if (entityListModel.getSize() == 1) {
				removeEntityButton.setEnabled(true);
			}
		}
	}

	private String validateFileName(String fileName) {
		String str = null;
		int index = -1;
		if (fileName.indexOf(".txt") != -1) {
			index = fileName.lastIndexOf(fileSeparator);
			if (index != -1) {
				str = fileName.substring(index + 1);
			} else {
				str = fileName;
			}
		}
		return str;
	}

	private void selectMap() {
		selectFile(mapTextField);
	}

	private void selectEntityImage() {
		selectFile(entityImageTextField);
	}

	private void selectequipmentImage() {
		selectFile(equipmentIamgeTextField);
	}

	private void selectFile(JTextField textField) {
		int returnVal = fileChooser.showOpenDialog(this);
		File file = null;
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			file = fileChooser.getSelectedFile();
			textField.setText(file.getAbsolutePath());
		}
	}

	public static void alertMessage(String message) {
		JOptionPane.showMessageDialog(null, message, "Alert",
				JOptionPane.INFORMATION_MESSAGE);
	}

	public String getPropertyFolderRoot() {
		return "user_simulation";
	}

	public String getSimulationName() {
		return nameTextField.getText().trim();
	}

	void setEnableEntityPropertyButtton(Boolean value) {
		createEntityProperty.setEnabled(value);
		if ((equipmentPropertyPanel).getEquipmentIsCreated() && !value) {
			createSimulationButton.setEnabled(true);
		}
	}

	void setEnableEquipmentPropertyButtton(Boolean value) {
		createEquipmentProperty.setEnabled(value);
		if ((entityPropertyPanel).getEntityIsCreated() && !value) {
			createSimulationButton.setEnabled(true);
		}
	}

	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}
		// The directory is now empty so delete it
		return dir.delete();
	}

	public static void copy(String fromFileName, String toFileName)
			throws IOException {
		File fromFile = new File(fromFileName);
		File toFile = new File(toFileName);
		Boolean continueToCopy = true;

		if (!fromFile.exists()) {
			continueToCopy = false;
			alertMessage("FileCopy: no such source file: " + fromFileName);
		}

		if (!fromFile.isFile()) {
			continueToCopy = false;
			alertMessage("FileCopy: " + "can't copy directory: " + fromFileName);
		}

		if (!fromFile.canRead()) {
			continueToCopy = false;
			alertMessage("FileCopy: " + "source file is unreadable: "
					+ fromFileName);
		}

		if (toFile.isDirectory()) {
			toFile = new File(toFile, fromFile.getName());
		}

		if (toFile.exists()) {
			if (!toFile.canWrite()) {
				continueToCopy = false;
				alertMessage("FileCopy: " + "destination file is unwriteable: "
						+ toFileName);
			}

			int option = JOptionPane.showConfirmDialog(null,
					"Overwrite existing file?", "Confirm Overwrite",
					JOptionPane.YES_NO_OPTION);
			if (option != JOptionPane.OK_OPTION) {
				continueToCopy = false;
				alertMessage("FileCopy: "
						+ "existing file was not overwritten.");
			}
		} else {
			String parent = toFile.getParent();
			if (parent == null)
				parent = System.getProperty("user.dir");
			File dir = new File(parent);

			if (!dir.exists()) {
				continueToCopy = false;
				alertMessage("FileCopy: "
						+ "destination directory doesn't exist: " + parent);
			}

			if (dir.isFile()) {
				continueToCopy = false;
				alertMessage("FileCopy: " + "destination is not a directory: "
						+ parent);
			}

			if (!dir.canWrite()) {
				continueToCopy = false;
				alertMessage("FileCopy: "
						+ "destination directory is unwriteable: " + parent);
			}
		}

		if (continueToCopy) {
			FileInputStream from = null;
			FileOutputStream to = null;
			try {
				from = new FileInputStream(fromFile);
				to = new FileOutputStream(toFile);
				byte[] buffer = new byte[4096];
				int bytesRead;

				while ((bytesRead = from.read(buffer)) != -1)
					to.write(buffer, 0, bytesRead); // write
			} finally {
				if (from != null)
					try {
						from.close();
					} catch (IOException e) {
						alertMessage(e.getMessage());
					}
				if (to != null)
					try {
						to.close();
					} catch (IOException e) {
						alertMessage(e.getMessage());
					}
			}
		}

	}
}
